package org.rayson.client.transport;

import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.locks.Lock;

import org.rayson.share.transport.Connection;
import org.rayson.share.transport.NioSelector;

public class ClientSelector extends NioSelector {

	private Lock acceptLock;

	private List<Runnable> acceptTask;

	public ClientSelector(Selector selector, String name) {
		super(selector, name);
	}

	public void accept(final Connection conn) {
		acceptLock.lock();
		try {
			acceptTask.add(new Runnable() {

				@Override
				public void run() {

					try {
						conn.getChannel().registerInterest(
								SelectionKey.OP_ACCEPT);

					} catch (Exception e) {
						// TODO: handle exception
					}

				}
			});
			selector.wakeup();

		} finally {
			acceptLock.unlock();
		}
	}

	private void pollAcceptTasks() {
		acceptLock.lock();
		try {
			if (acceptTask.isEmpty())
				return;

			for (Iterator<Runnable> iter = acceptTask.iterator(); iter
					.hasNext();) {
				Runnable task = iter.next();
				iter.remove();

				try {
					task.run();

				} catch (Exception e) {
					continue;
				}
			}

		} finally {
			acceptLock.unlock();
		}

	}

	@Override
	public void run() {
		SelectionKey sk = null;
		while (true) {

			try {
				pollAcceptTasks();
				pollSupplementReads();
				pollSupplementWrites();

				selector.select();

				for (Iterator<SelectionKey> iter = selector.selectedKeys()
						.iterator(); iter.hasNext();) {
					sk = iter.next();
					iter.remove();
					try {

						if (!sk.isValid())
							continue;
						if (sk.isConnectable())
							doConnect(sk);
						else if (sk.isReadable())
							doRead(sk);
						else if (sk.isWritable())
							doWrite(sk);

					} catch (Exception e) {
						continue;
					}

				}

			} catch (OutOfMemoryError e) {

			} catch (Throwable e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
	}

}
